Generar URL de manera segura

Descripcion

Como generar URLs de manera que no contengan un formato invalido (como caracteres / de mas).

Metodo

Tenemos que tener en cuenta que podemos tener dos situaciones a la hora de crear una URL.

En algunos proyecto puede ser necesario crear solo el path, ya que el dominio se añade posteriormente con un interceptor.

Generar path

Para generar el path de manera segura tenemos que utilizar el paquete url-join, lo instalamos de la siguiente manera:

npm install url-join

Una vez instalado lo podemos utilizar de la siguiente manera:

import urlJoin from 'url-join';
const fullpath = urlJoin('/ejemplo/', '/ejemplo2');
console.log(fullpath)

Este código genera como salida:

/ejemplo/ejemplo2

A pesar de que hemos puesto una barra al final de "ejemplo" y una al principio de "ejemplo2", la función elimina la barra de más.

Tambien podemos indicar a mayores el dominio y parámetros si queremos:

urlJoin('http://www.google.com', 'a', '/b/cd', '?foo=123');

Aunque para añadir parámetros es mejor usar una clase URL o HttpParams como veremos a continuación.

Nota: el uso del modulo path de node no es recomendado, porque en sistemas windows las barras son invertidas.

Añadir parámetros

Para añadir parámetros a una URL podemos hacerlo de dos maneras:

Usaremos una clase URL cuando queremos indicar la ruta entera (indicando el dominio):

const fullpath = urlJoin('/ejemplo/', '/ejemplo2');
const myUrl = new URL(fullpath, "http://midominio.com/")

myUrl.searchParams.append("parametro1", "valor1")
myUrl.searchParams.append("parametro2", "valor2")

console.log(myUrl.toString())

Este código genera la siguiente salida:

http://midominio.com/ejemplo/ejemplo2?parametro1=valor1&parametro2=valor2

La URL se genera correctamente a pesar de que hay barras al final del dominio y al principio de los paths (no hay barras duplicadas).

La otra manera de añadir parámetros es usando HttpParams, normalmente esto lo usaremos cuando solo trabajamos con el path, y los params se pasará a la llamada GET que realicemos:

const fullpath = urlJoin('/ejemplo/', '/ejemplo2');

let params = new HttpParams()
    
params = params.append("parametro1", "valor1")
params = params.append("parametro2", "valor2")

return this.http.get<string>(fullpath, {params})

El metodo GET llamará a la siguiente URL en este caso:

http://localhost:4200/ejemplo/ejemplo2?parametro1=valor1&parametro2=valor2

El HttpParams tambien lo podemos usar cuando usamos la clase URL, pero en ese caso como la propia clase nos permite añadir parámetros pues nos ahorramos el HttpParams, en ese caso solo tendríamos que pasar la URL a la llamada GET, ya que la propia URL incluiría los parametros.

NOTA: hay que fijarse en que params.append se iguala a params ya que la función devuelve una nueva referencia con el nuevo valor actualizado y no lo actualiza en la referencia actual.

Metodo (Deprecated)

Para generar URLs de manera seguro lo hacemos de la siguiente manera:

  ngOnInit(){

    const path = require('path');

    const baseUrl = 'ejemplo.com';
    const pathExtra1 = 'ejemplo';
    const pathExtra2 = 'dos';

    const fullUrl: string = new URL(path.join(pathExtra1, pathExtra2, pathExtra1), baseUrl).toString();

    console.log(fullUrl);
  }

Primero importamos el modulo path (Si usamos una versión de angular 12 o superior tendremos un problema con esto, explicado en troubleshooting), despues simplemente usamos path.join para unir todos los trozos de la ruta y creamos un objeto URL para unir la dirección base con toda la ruta que ha generado el path.join, esto nos generará un string resultante como el siguiente:

http://ejemplo.com/ejemplo/dos/ejemplo

La URL es correcta, no tiene barras (/) de más, cosa que podría suceder si usasemos el operador + e intentamos concatenar por ejemplo "/ejemplo/" y "/ejemplo2" la url resultante sería algo como "/ejemplo//ejemplo2" dando lugar a una url invalida.

Query parameters

A mayores tambien podemos añadir parámetros a la url usando el tipo URL, se haría de la siguiente manera:

    let myPath = "/api/usuarios";
    let server = "http://127.0.0.1/";

    let myURL = new URL(myPath, server);
    myURL.searchParams.append("page", "1");
    myURL.searchParams.append("size", "10");

    console.log(myURL.toString())

Este código nos generaría la siguiente URL:

http://127.0.0.1/api/usuarios?page=1&size=10
Troubleshooting

Si usamos angular 12 o superior obtendremos un error al intentar hacer el require del modulo path:

./src/app/app.component.ts:46:13-28 - Error: Module not found: Error: Can't resolve 'path' in 'C:\Users\manuel.bascoy\lab\AngularDeploy\src\app'

BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.

If you want to include a polyfill, you need to:
        - add a fallback 'resolve.fallback: { "path": require.resolve("path-browserify") }'
        - install 'path-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
        resolve.fallback: { "path": false }

Para solucionar este problema primero tenemos que instalar el siguiente modulo:

npm install path-browserify

Y a continuación en el archivo tsconfig.json, introducir la siguiente configuración dentro del apartado "compilerOptions":

"paths": {
  "path": [
    "./node_modules/path-browserify"
  ]
}
Tags

Angular | URL |